import { Size } from "./base/size";
import {
  Scene,
  PerspectiveCamera,
  WebGLRenderer,
  TextureLoader,
  Texture,
  EquirectangularReflectionMapping,
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import ObjectFactory from "./ObjectFactory";
import createModel from "./base/model";
import createScene from "./base/scene";
import createCamera from "./base/camera";
import { createLight } from "./base/light";
import { onWindowResize } from "./base/resize";

interface ThreeToolsOptions {
  onLoadProgress?: (progress: {
    progress: number;
    loaded: number;
    total: number;
  }) => void;
  onLoadComplete?: () => void;
}

/**
 * Three.js 工具类
 * 用于管理 Three.js 场景、相机、渲染器和控制器等核心组件
 */
export default class ThreeTools {
  /** Three.js 场景实例 */
  public scene: Scene;
  /** 透视相机实例 */
  public camera: PerspectiveCamera;
  /** WebGL 渲染器实例 */
  public renderer: WebGLRenderer;
  /** Canvas DOM 元素 */
  public canvas: HTMLCanvasElement;
  /** 轨道控制器实例 */
  public controls: OrbitControls;
  private options: ThreeToolsOptions;

  /**
   * 构造函数
   * @param canvas - 用于渲染的 Canvas 元素
   */
  constructor(canvas: HTMLCanvasElement, options: ThreeToolsOptions = {}) {
    this.canvas = canvas;
    this.options = options;
    this.scene = createScene();
    this.camera = createCamera({
      fov: 50,
      aspect: Size.aspect,
      near: 1,
      far: 2000,
      position: { x: -2.95, y: 1.33, z: 3.91 },
    });

    // 初始化渲染器
    this.renderer = new WebGLRenderer({
      canvas: this.canvas,
      antialias: true,
      alpha: true,
    });
    this.renderer.setSize(window.innerWidth, window.innerHeight);
    this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    this.renderer.setClearColor(0x000000, 0); // 设置透明背景
    this.renderer.shadowMap.enabled = true; // 启用阴影
    // 添加灯光效果
    createLight(this.scene);
    // 初始化控制器
    this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    this.controls.enableDamping = true;
    this.controls.dampingFactor = 0.05;
    // 添加窗口大小改变监听
    window.addEventListener(
      "resize",
      onWindowResize(this.camera, this.renderer)
    );
    // 开始渲染循环
    this.animate = this.animate.bind(this);
    this.animate();

    // 加载模型
    this.loadModel();
  }

  private async loadModel() {
    try {
      await createModel(this.scene, (progress) => {
        this.options.onLoadProgress?.(progress);
      });
      this.options.onLoadComplete?.();
    } catch (error) {
      console.error("Failed to load model:", error);
    }
  }

  /**
   * 动画循环
   * 更新控制器状态并渲染场景
   */
  private animate = () => {
    // 请求下一帧动画
    requestAnimationFrame(this.animate);

    // 更新控制器
    if (this.controls) {
      this.controls.update();
    }

    // 渲染场景
    if (this.renderer && this.scene && this.camera) {
      try {
        this.renderer.clear();
        this.renderer.render(this.scene, this.camera);
      } catch (error) {
        console.error("Render error:", error);
      }
    }
  };

  /**
   * 添加立方体到场景
   * @param options - 立方体配置选项
   * @returns 创建的立方体实例
   */
  public addCube(options = {}) {
    const cube = ObjectFactory.createCube(options);
    this.scene.add(cube);
    return cube;
  }

  /**
   * 添加球体到场景
   * @param options - 球体配置选项
   * @returns 创建的球体实例
   */
  public addSphere(options = {}) {
    const sphere = ObjectFactory.createSphere(options);
    this.scene.add(sphere);
    return sphere;
  }

  /**
   * 添加圆柱体到场景
   * @param options - 圆柱体配置选项
   * @returns 创建的圆柱体实例
   */
  public addCylinder(options = {}) {
    const cylinder = ObjectFactory.createCylinder(options);
    this.scene.add(cylinder);
    return cylinder;
  }

  /**
   * 创建环境贴图
   * @param imagePath - 环境贴图图片路径
   * @returns 环境贴图实例
   */
  public createEnvironmentMap(imagePath: string) {
    const textureLoader = new TextureLoader();

    return new Promise<Texture>((resolve, reject) => {
      textureLoader.load(
        imagePath,
        (texture) => {
          texture.mapping = EquirectangularReflectionMapping;
          this.scene.environment = texture;
          this.scene.background = texture;
          this.renderer.toneMappingExposure = 1.0;
          resolve(texture);
        },
        undefined,
        reject
      );
    });
  }

  /**
   * 更新环境贴图
   * @param texture - 环境贴图实例
   */
  public updateEnvironmentMap(texture: Texture | null) {
    this.scene.environment = texture;
    this.scene.background = texture;
  }

  /**
   * 移除环境贴图
   */
  public removeEnvironmentMap() {
    this.scene.environment = null;
    this.scene.background = null;
  }

  /**
   * 设置环境贴图的强度
   * @param exposure - 曝光值 (0.0 - 2.0)
   */
  public setEnvironmentIntensity(exposure: number) {
    if (this.renderer) {
      this.renderer.toneMappingExposure = Math.max(0, Math.min(2, exposure));
    }
  }
}
